home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland Pascal with Objects 7.0 / PAINT.ZIP / CANVAS.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1992-10-27  |  20.0 KB  |  736 lines

  1. {************************************************}
  2. {                                                }
  3. {   ObjectWindows Paint demo                     }
  4. {   Copyright (c) 1992 by Borland International  }
  5. {                                                }
  6. {************************************************}
  7.  
  8. unit Canvas;
  9.  
  10. { This unit supplies the drawing canvas for the paint program, that is, the
  11.   window where drawing actually takes place.
  12.  
  13.   The Canvas is responisble for maintaining the screen state, including
  14.   updating the cursor, directing input to the currently selected drawing
  15.   tool and managing the enabling of certain menu items (cut/copy/paste/etc).
  16. }
  17.  
  18. interface
  19.  
  20. uses PaintDef, ResDef, Bitmaps, WinTypes, WinProcs, Strings, OWindows;
  21.  
  22. type
  23.  
  24.   PCanvas = ^TCanvas;
  25.   TCanvas = object(TWindow)
  26.     State: PState;
  27.  
  28.     Bitmap: HBitmap;        { Save the bitmap originally in State^.MemDC }
  29.     UndoBitmap: HBitmap;    { Saved bitmap for undoing }
  30.     UndoDC: HDC;        { Display context for undoing }
  31.  
  32.     Drawing: Boolean;        { In the process of drawing }
  33.     OverSelection: Boolean;    { Cursor is the 'over selection' cursor }
  34.  
  35.     { Creation and destruction }
  36.     constructor Init(AParent: PWindowsObject; AState: PState);
  37.     destructor Done; virtual;
  38.     procedure SetupWindow; virtual;
  39.     procedure NewBitmaps(DC: HDC);
  40.  
  41.     { Display }
  42.     procedure MoveSelf(WX, WY, WW, WH: Integer; Repaint: Boolean);
  43.     procedure Paint(PaintDC: HDC; var PaintInfo: TPaintStruct); virtual;
  44.     procedure PaintSelection(DC: HDC; AddOffset: Boolean);
  45.     procedure SaveUndo;
  46.  
  47.     { Menu management }
  48.     { Cut/Copy/Paste }
  49.     procedure EnableCCDMenu(mf_Flag: Integer);
  50.     procedure EnableCCD;
  51.     procedure DisableCCD;
  52.  
  53.     { Undo/Redo }
  54.     procedure EnableUndoMenu(mf_Flag: Integer);
  55.     procedure EnableUndo;
  56.     procedure DisableUndo;
  57.     procedure ResetUndoLabel(NewLabel: PChar);
  58.  
  59.     { Menu initiated actions }
  60.     { File }
  61.     procedure Undo;
  62.     function Load(FileName: PChar): Integer;
  63.     function Store(FileName: PChar): Integer;
  64.  
  65.     { Edit }
  66.     procedure CopyToClipBoard(DC: HDC; Left, Top, Width, Height: Integer);
  67.     procedure Erase(Left, Top, Width, Height: Integer);
  68.     procedure PickUpSelection(aDC: HDC; Left, Top, Width, Height: Integer);
  69.     procedure ReleaseSelection;
  70.  
  71.     procedure Cut;
  72.     procedure Copy;
  73.     procedure Paste;
  74.     procedure Delete;
  75.     procedure ClearAll;
  76.  
  77.     { Options }
  78.     procedure Resize(CopyFlag: Integer);
  79.     procedure BitmapCopy(aBitmap: HBitmap; CopyFlag: Integer);
  80.  
  81.     { Window manager responses }
  82.     { Mouse initiated actions }
  83.     procedure WMLButtonDown(var Msg: TMessage);
  84.       virtual wm_First + wm_LButtonDown;
  85.     procedure WMLButtonUp(var Msg: TMessage);
  86.       virtual wm_First + wm_LButtonUp;
  87.     procedure WMMouseMove(var Msg: TMessage);
  88.       virtual wm_First + wm_MouseMove;
  89.     procedure wmSetCursor(var Msg: TMessage);
  90.       virtual wm_First + wm_SetCursor;
  91.  
  92.   end;
  93.  
  94.   PCanvasScroller = ^TCanvasScroller;
  95.   TCanvasScroller = object(TScroller)
  96.     procedure BeginView(PaintDC: HDC; var PaintInfo: TPaintStruct); virtual;
  97.   end;
  98.  
  99. implementation
  100.  
  101. { Create a new canvas and initialize the selection.
  102. }
  103. constructor TCanvas.Init(AParent: PWindowsObject; AState: PState);
  104. var
  105.   DC: HDC;
  106. begin
  107.   TWindow.Init(AParent, nil);
  108.   Attr.Style := ws_Border or ws_Child or ws_Visible
  109.         or ws_HScroll or ws_VScroll;
  110.   Scroller := New(PCanvasScroller, Init(@Self, 1, 1, 200, 200));
  111.   State := AState;
  112.   
  113.   { Initialize the selection }
  114.   SetRectEmpty(State^.Selection);
  115.   State^.SelectionBM := 0;
  116.  
  117.   Drawing := False;
  118.   OverSelection := False;
  119.  
  120.   State^.IsDirtyBitmap := False;
  121. {  DisableUndo;}
  122.  
  123.   { Set up the display contexts }
  124.   DC := GetDC(0);
  125.   State^.MemDC := CreateCompatibleDC(DC);
  126.   UndoDC       := CreateCompatibleDC(DC);
  127.  
  128.   { Create the bitmaps }
  129.   NewBitmaps(DC);
  130.  
  131.   ReleaseDC(0, DC);
  132. end;
  133.  
  134. { Destroy the off-screen bitmaps before dying.
  135. }
  136. destructor TCanvas.Done;
  137. begin
  138.   DeleteObject(SelectObject(State^.MemDC, Bitmap));
  139.   DeleteObject(SelectObject(UndoDC, UndoBitmap));
  140.   DeleteDC(State^.MemDC);
  141.   DeleteDC(UndoDC);
  142.   if State^.SelectionBM <> 0 then DeleteObject(State^.SelectionBM);
  143.   TWindow.Done;
  144. end;
  145.  
  146. procedure TCanvas.SetupWindow;
  147. begin
  148.   TWindow.SetupWindow;
  149.   DisableUndo;
  150. end;
  151.  
  152. { Set up new bitmaps for the canvas. It is assumed that the DCs have already
  153.   been set up appropriately.
  154. }
  155. procedure TCanvas.NewBitmaps(DC: HDC);
  156. begin
  157.   with State^.BitmapSize do
  158.     begin
  159.       Bitmap     := SelectObject(State^.MemDC, 
  160.                          CreateCompatibleBitmap(DC, X, Y));
  161.       UndoBitmap := SelectObject(UndoDC, 
  162.                              CreateCompatibleBitmap(DC, X, Y));
  163.  
  164.       { White them out }
  165.       PatBlt(State^.MemDC, 0, 0, X, Y, whiteness);
  166.       PatBlt(UndoDC,       0, 0, X, Y, whiteness);
  167.    end;
  168. end;
  169.  
  170. { Display }
  171. { Move and resize the window. Adjust the Scroller as needed.
  172. }
  173. procedure TCanvas.MoveSelf(WX, WY, WW, WH: Integer; Repaint: Boolean);
  174. var
  175.   XRange, YRange: Integer;
  176. begin
  177.   with State^.BitmapSize do
  178.   begin
  179.     if WW > X + 2 then
  180.     begin
  181.       XRange := 0;
  182.       WW := X + 2;
  183.     end
  184.     else
  185.       XRange := X - WW;
  186.  
  187.     if WH > Y + 2 then
  188.     begin
  189.      YRange := 0;
  190.      WH := Y + 2;
  191.     end
  192.     else
  193.       YRange := Y - WH;
  194.   end;
  195.  
  196.   { Windows' MoveWindow does not repaint the window if the given
  197.     coordinates are exactly the same as the current coordinates. }
  198.   if (Attr.X = WX) and (Attr.Y = WY) and (Attr.W = WW)
  199.      and (Attr.H = WH) and Repaint then
  200.     InvalidateRect(HWindow, nil, True)
  201.   else
  202.     MoveWindow(HWindow, WX, WY, WW, WH, Repaint);
  203.  
  204.   { When one of the parameters is zero and the other unchanged, the
  205.     corresponding scrollbar is eliminated. }
  206.  
  207.   Scroller^.SetRange(XRange, Scroller^.YRange);
  208.   Scroller^.SetRange(Scroller^.XRange, YRange);
  209.   Scroller^.ScrollTo(0, 0);
  210. end;
  211.  
  212. { Update the screen display from the off-screen bitmap. Highlight the 
  213.   selection if there is one.
  214. }
  215. procedure TCanvas.Paint(PaintDC: HDC; var PaintInfo: TPaintStruct);
  216. var
  217.   R: TRect;            { The window client area }
  218. begin
  219.   { Copy from the off-screen bitmap to the screen }
  220.   GetClientRect(HWindow, R);
  221.   BitBlt(PaintDC, 0, 0, State^.BitmapSize.X, State^.BitmapSize.Y, 
  222.     State^.MemDC, 0, 0, SrcCopy);
  223.  
  224.   { Highlight the selection }  
  225.   PaintSelection(PaintDC, True);
  226. end;
  227.  
  228. { Highlight the selection, if there is one, by drawing a dotted line around
  229.   it. If there is a selection bitmap display it. Add the Offset in State
  230.   to the coordinates if requested.
  231. }
  232. procedure TCanvas.PaintSelection(DC: HDC; AddOffset: Boolean);
  233. var
  234.   SelDC: HDC;            { For the selection bitmap }
  235.   XOffset, YOffset: Integer;    { The offsets to be used }
  236. begin
  237.   if not IsRectEmpty(State^.Selection) then
  238.   begin
  239.     XOffset := 0;
  240.     YOffset := 0;
  241.     if AddOffset then
  242.     begin
  243.       XOffset := State^.Offset.X;
  244.       YOffset := State^.Offset.Y;
  245.     end;
  246.  
  247.     { Draw the selecton bitmap }
  248.     if State^.SelectionBM <> 0 then
  249.     begin
  250.  
  251.       { Set up the drawing context }
  252.       SelDC := CreateCompatibleDC(DC);
  253.       State^.SelectionBM := SelectObject(SelDC, State^.SelectionBM);
  254.  
  255.       { Copy the bits to the screen }
  256.       with State^.Selection do
  257.     BitBlt(DC, Left + XOffset, Top + YOffset, Right - Left,
  258.           Bottom - Top, SelDC, 0, 0, SrcCopy);
  259.  
  260.       { Clean up }
  261.       State^.SelectionBM := SelectObject(SelDC, State^.SelectionBM);
  262.       DeleteDC(SelDC);
  263.     end;
  264.  
  265.     { Draw a dotted line marking the selected area }
  266.     SetROP2(DC, r2_CopyPen);
  267.     SelectObject(DC, DashedPen);
  268.     SelectObject(DC, GetStockObject(Null_Brush));
  269.     with State^.Selection do
  270.       Rectangle(DC, Left + XOffset, Top + YOffset, Right + XOffset,
  271.         Bottom + YOffset);
  272.   end;
  273. end;
  274.  
  275. { Save the potentially modified portion of the current bitmap on the
  276.   undo bitmap and enable undoing.
  277. }
  278. procedure TCanvas.SaveUndo;
  279. begin
  280.   { Save the current bitmap as the undo bitmap }
  281.   BitBlt(UndoDC, 0, 0, State^.BitmapSize.X, State^.BitmapSize.Y,
  282.     State^.MemDC, 0, 0, SrcCopy);
  283.   EnableUndo;
  284. end;
  285.  
  286.  
  287. { Menu management }
  288. { Enable/Disable the cut/copy/delete menu items.
  289. }
  290. procedure TCanvas.EnableCCDMenu(mf_Flag: Integer);
  291. var
  292.   Menu: HMenu;
  293. begin
  294.   Menu := GetMenu(Parent^.HWindow);
  295.   EnableMenuItem(Menu, cm_EditCut, mf_Flag);
  296.   EnableMenuItem(Menu, cm_EditCopy, mf_Flag);
  297.   EnableMenuItem(Menu, cm_EditDelete, mf_Flag);
  298. end;
  299.  
  300. procedure TCanvas.EnableCCD;
  301. begin
  302.   EnableCCDMenu(mf_Enabled);
  303. end;
  304.  
  305. procedure TCanvas.DisableCCD;
  306. begin
  307.   EnableCCDMenu(mf_Grayed);
  308. end;
  309.  
  310. { Enable/Disable the undo menu item.
  311. }
  312. procedure TCanvas.EnableUndoMenu(mf_Flag: Integer);
  313. var
  314.   Menu: HMenu;
  315. begin
  316.   Menu := GetMenu(Parent^.HWindow);
  317.   ModifyMenu(Menu, cm_EditUndo, mf_ByCommand or mf_String,
  318.     cm_EditUndo, '&Undo');
  319.   EnableMenuItem(Menu, cm_EditUndo, mf_Flag);
  320. end;
  321.  
  322. procedure TCanvas.EnableUndo;
  323. begin
  324.   EnableUndoMenu(mf_Enabled);
  325. end;
  326.   
  327. procedure TCanvas.DisableUndo;
  328. begin
  329.   EnableUndoMenu(mf_Grayed);
  330. end;
  331.  
  332. procedure TCanvas.ResetUndoLabel(NewLabel: PChar);
  333. begin
  334.   ModifyMenu(GetMenu(Parent^.HWindow), cm_EditUndo, mf_ByCommand or mf_String,
  335.     cm_EditUndo, NewLabel);
  336. end;
  337.  
  338.  
  339. { Menu initiated functions }
  340. { File }
  341.  
  342. { Undo the last change to the current bitmap and toggle the undo/redo menu
  343.   item.
  344. }
  345. procedure TCanvas.Undo;
  346. var
  347.   MLabel: String[6];         { The current undo/redo label }
  348.   R: TRect;            { The window client area }
  349. begin
  350.   { Swap the bitmaps in the DCs }
  351.   Bitmap := SelectObject(State^.MemDC, SelectObject(UndoDC,
  352.     SelectObject(State^.MemDC, Bitmap)));
  353.  
  354.   { Reset the undo/redo label }
  355.   GetMenuString(GetMenu(Parent^.HWindow), cm_EditUndo, @MLabel, 6,
  356.     mf_ByCommand);
  357.   if StrComp(@MLabel, '&Undo') = 0 then
  358.     ResetUndoLabel('&Redo')
  359.   else
  360.     ResetUndoLabel('&Undo');
  361.  
  362.   { Update the screen }
  363.   GetClientRect(HWindow, R);
  364.   InvalidateRect(HWindow, @R, False);
  365. end;  
  366.  
  367. { Read a bitmap from a file into the current drawing canvas. Returns 0 on 
  368.   error, otherwise non-zero.
  369. }
  370. function TCanvas.Load(FileName: PChar): Integer;
  371.  
  372.   function Smaller(A, B: Integer): Integer;
  373.   begin
  374.     if A < B then Smaller := A else Smaller := B;
  375.   end;
  376.  
  377. var
  378.   HBM: HBitmap;            { The new bitmap }
  379.   BM: TBitmap;            { Information about the new bitmap }
  380. begin
  381.   Load := 1;
  382.  
  383.   { Actually read in the bitmap }
  384.   HBM := LoadBitmapFile(FileName);
  385.   if HBM = 0 then        { Failure }
  386.   begin
  387.     Load := 0;
  388.     Tell('Unable to read bitmap.');
  389.     exit;
  390.   end;
  391.  
  392.   { Mark the bitmap as unmodified, and clear the selection }
  393.   State^.IsDirtyBitmap := False;
  394.   DisableUndo;
  395.   SetRectEmpty(State^.Selection);
  396.  
  397.   { Reconfigure the world to suit the new bitmap size }
  398.   GetObject(HBM, sizeOf(BM), @BM);    { Information about the new bitmap }
  399.   with State^.BitmapSize do
  400.   begin
  401.     X := BM.bmWidth;
  402.     Y := BM.bmHeight;
  403.   end;
  404.   DeleteObject(SelectObject(State^.MemDC, HBM));
  405.   DeleteObject(SelectObject(UndoDC, CreateCompatibleBitmap(UndoDC,
  406.     State^.BitmapSize.X, State^.BitmapSize.Y)));
  407. end;
  408.  
  409. { Write the current image out to a file. Returns 0 if error, otherwise
  410.   non-zero.
  411. }
  412. function TCanvas.Store(FileName: PChar): Integer;
  413. var 
  414.   I: Integer;            { Result from the actual write }
  415. begin
  416.   { Retrieve the actual bitmap from the State display context }
  417.   Bitmap := SelectObject(State^.MemDC, Bitmap);
  418.   I := StoreBitmapFile(FileName, Bitmap);
  419.   
  420.   { Restore the off-screen bitmap to the State display context }
  421.   Bitmap := SelectObject(State^.MemDC, Bitmap);
  422.  
  423.   State^.IsDirtyBitmap := I <> 1; { Mark the bitmap unmodified if successful }
  424.   DisableUndo;
  425.   Store := I;
  426. end;
  427.  
  428. { Edit }
  429.  
  430. { Copy the indicated bits of bitmap in the drawing context to the clipboard.
  431.   Copying to the clipboard is done by transferring a bitmap to the clipboard.
  432.   Once the clipboard has been passed this bitmap, it is no longer owned by
  433.   the application, so a new bitmap is created expressly for this purpose.
  434. }
  435. procedure TCanvas.CopyToClipBoard(DC: HDC; Left, Top, Width, Height: Integer);
  436. var
  437.   CopyDC: HDC;            { For the new bitmap }
  438.   CopyBitmap: HBitmap;        { The new bitmap }
  439. begin
  440.   { Make sure clipboard is available and can be copied to }
  441.   if OpenClipBoard(HWindow) and EmptyClipBoard then
  442.   begin
  443.  
  444.     { Create the new bitmap }
  445.     CopyDC := CreateCompatibleDC(DC);
  446.     CopyBitmap := CreateCompatibleBitmap(DC, Width, Height);
  447.     CopyBitmap := SelectObject(CopyDC, CopyBitmap);
  448.     BitBlt(CopyDC, 0, 0, Width, Height, DC, Left, Top, SrcCopy);
  449.     CopyBitmap := SelectObject(CopyDC, CopyBitmap);
  450.  
  451.     { Transfer the new bitmap to the clipboard }
  452.     SetClipBoardData(cf_Bitmap, CopyBitmap);
  453.  
  454.     { Clean up }
  455.     CloseClipBoard;
  456.     DeleteDC(CopyDC);
  457.   end;
  458. end;
  459.  
  460. { White out the rectangle indicated on the off-screen bitmap.
  461. }
  462. procedure TCanvas.Erase(Left, Top, Width, Height: Integer);
  463. begin
  464.   { White out the rectangle }
  465.   PatBlt(State^.MemDC, Left, Top, Width, Height, Whiteness);
  466. end;
  467.  
  468. { Make the current selection into a selection bitmap. Note that this should
  469.   (and can be) only invoked when the SelectTool is active. (Otherwise there
  470.   could be no selection.
  471. }
  472. procedure TCanvas.PickUpSelection(aDC: HDC; Left, Top, Width, Height: Integer);
  473. begin
  474.   State^.PaintTool^.PickUpSelection(aDC, Left, Top, Width, Height);
  475. end;
  476.  
  477. { Release the current selection without saving the bits. Also gray out the
  478.   appropriate menu items.
  479. }
  480. procedure TCanvas.ReleaseSelection;
  481. begin
  482.   State^.PaintTool^.ReleaseSelection;
  483.   DisableCCD;
  484. end;
  485.  
  486. { Copy the current selection to the clipboard and white out the hole.
  487. }
  488. procedure TCanvas.Cut;
  489. begin
  490.   Copy;
  491.   Delete;
  492. end;
  493.  
  494. { Copy the current selection to the clipboard.
  495. }
  496. procedure TCanvas.Copy;
  497. begin
  498.   if State^.SelectionBM <> 0 then
  499.     
  500.     { Use the selection bitmap }
  501.     begin
  502.       State^.SelectionBM := SelectObject(State^.MemDC, State^.SelectionBM);
  503.       with State^.Selection do
  504.         CopyToClipBoard(State^.MemDC, 0, 0, Right-Left, Bottom-Top);
  505.       State^.SelectionBM := SelectObject(State^.MemDC, State^.SelectionBM);
  506.     end
  507.   else
  508.     
  509.     { Copy from the off-screen bitmap }
  510.     begin
  511.       with State^.Selection do
  512.         CopyToClipBoard(State^.MemDC, Left, Top, Right-Left, Bottom-Top);
  513.     end;
  514.     DisableUndo;
  515. end;
  516.  
  517. { Retrieve what is in the clipboard and make it the current selection bitmap.
  518.   The clipboard retains ownership of the retrieved bitmap, so it must be
  519.   copied into a new selection bitmap.
  520. }
  521. procedure TCanvas.Paste;
  522. var
  523.   DC, ClipDC: HDC;        { For screen and clipboard bitmaps }
  524.   ClipBitmap: HBitmap;        { The clipboard bitmap }
  525.   BM: TBitmap;            { Information on the clipboard bitmap }
  526. begin
  527.  
  528.   { Make sure the clipboard is available }
  529.   if OpenClipBoard(HWindow) then
  530.   begin
  531.  
  532.     { Set up the drawing contexts }
  533.     DC := GetDC(HWindow);
  534.     ClipDC := CreateCompatibleDC(DC);
  535.  
  536.     { Retrieve the clipboard bitmap }
  537.     ClipBitmap := GetClipBoardData(cf_Bitmap);
  538.     CloseClipBoard;
  539.  
  540.     { Make sure the retrieve succeeded and make it the selection bitmap }
  541.     if (ClipBitmap <> 0) and
  542.        { Get information about the bitmap }
  543.        (GetObject(ClipBitmap, SizeOf(TBitmap), @BM) <> 0) then
  544.     begin
  545.       ClipBitmap := SelectObject(ClipDC, ClipBitmap);
  546.       PickUpSelection(ClipDC, 0, 0, bm.bmWidth, bm.bmHeight);
  547.       ClipBitmap := SelectObject(ClipDC, ClipBitmap);
  548.       PaintSelection(DC, False);
  549.       DisableUndo;
  550.     end;
  551.  
  552.     { Clean up }
  553.     DeleteDC(ClipDC);
  554.     ReleaseDC(HWindow, DC);
  555.   end;
  556. end;
  557.  
  558. { White out the selected area or release the selection bitmap.
  559. }
  560. procedure TCanvas.Delete;
  561. begin
  562.   SaveUndo;
  563.   if State^.SelectionBM = 0 then
  564.     with State^.Selection do
  565.       Erase(Left, Top, Right-Left, Bottom-Top);
  566.   ReleaseSelection;
  567. end;
  568.  
  569. { White out the entire canvas.
  570. }
  571. procedure TCanvas.ClearAll;
  572. var
  573.   R: TRect;            { The window client area }
  574. begin
  575.   SaveUndo;
  576.   GetClientRect(HWindow, R);
  577.   InvalidateRect(HWindow, @R, False);
  578.   ReleaseSelection;
  579.   Erase(0, 0, State^.BitmapSize.X, State^.BitmapSize.Y);
  580. end;
  581.  
  582. { Options }
  583. { Resize the current bitmap by creating a new bitmap and copying the
  584.   contents of the current bitmap into it according to flag.
  585. }
  586. procedure TCanvas.Resize(CopyFlag: Integer);
  587. var
  588.   OBitmap: HBitmap;
  589.   DC: HDC;
  590. begin
  591.   DisableUndo;
  592.   OBitmap := SelectObject(State^.MemDC, Bitmap);
  593.   UndoBitmap := SelectObject(UndoDC, UndoBitmap);
  594.   DeleteObject(UndoBitmap);
  595.  
  596.   DC := GetDC(HWindow);
  597.   NewBitmaps(DC);
  598.   ReleaseDC(HWindow, DC);
  599.  
  600.   BitmapCopy(OBitmap, CopyFlag);
  601.  
  602.   DeleteObject(OBitmap);
  603. end;
  604.  
  605. { Copy the contents of bitmap into the current bitmap according to flag.
  606. }
  607. procedure TCanvas.BitmapCopy(aBitmap: HBitmap; CopyFlag: Integer);
  608. var
  609.   CopyDC: HDC;
  610.   BMinfo: TBitmap;
  611. begin
  612.   GetObject(aBitmap, SizeOf(TBitmap), @BMInfo);
  613.   CopyDC := CreateCompatibleDC(State^.MemDC);
  614.   aBitmap := SelectObject(CopyDC, aBitmap);
  615.   case CopyFlag of
  616.     id_StretchBM:
  617.       begin
  618.     StretchBlt(State^.MemDC, 0, 0, State^.BitmapSize.X,
  619.           State^.BitmapSize.Y, CopyDC, 0, 0, BMInfo.bmWidth,
  620.           BMInfo.bmHeight, SrcCopy);
  621.       end;
  622.     id_PadBM:
  623.       BitBlt(State^.MemDC, 0, 0, State^.BitmapSize.X, State^.BitmapSize.Y,
  624.         CopyDC, 0, 0, SrcCopy);
  625.   end;
  626.   aBitmap := SelectObject(CopyDC, aBitmap);
  627.   DeleteDC(CopyDC);  
  628. end;
  629.  
  630. { Window manager responses }
  631. { Mouse initiated actions }
  632.  
  633. { Start the selected drawing tool drawing.
  634. }
  635. procedure TCanvas.WMLButtonDown(var Msg: TMessage);
  636. begin
  637.   if not Drawing then
  638.   begin
  639.     { Let subsequent Mouse Moves and Mouse Ups know that drawing is in 
  640.       progress, i.e., that the initial mouse down occurred in the right
  641.       window.
  642.     }
  643.     Drawing := True;
  644.  
  645.     SaveUndo;
  646.     if IsRectEmpty(State^.Selection) then
  647.       State^.IsDirtyBitmap := True
  648.     else
  649.       DisableUndo;
  650.  
  651.     { Tell the current tool to start drawing }
  652.     State^.PaintTool^.MouseDown(HWindow, Integer(Msg.LParamLo),
  653.       Integer(Msg.LParamHi), State);
  654.   end;
  655. end;
  656.  
  657. { If drawing is in progress, tell the currently selected tool about the
  658.   Mouse Move.
  659. }
  660. procedure TCanvas.WMMouseMove(var Msg: TMessage);
  661. begin
  662.    if Drawing then
  663.        State^.PaintTool^.MouseMove(Integer(Msg.LParamLo),
  664.      Integer(Msg.LParamHi));
  665. end;
  666.  
  667. { If drawing is in progress, record the altered state of the image by either
  668.   copying the screen bitmap to the off-screen bitmap or high-lighting the
  669.   new selection. Tell the currently selected tool that the mouse is up.
  670.   Enable/disable menus appropriately.
  671. }
  672. procedure TCanvas.WMLButtonUp(var Msg: TMessage);
  673. var
  674.   DC: HDC;                { For the screen bitmap }
  675.   Menu: HMenu;                { For the window menu }
  676. begin
  677.   if Drawing then
  678.   begin
  679.     State^.PaintTool^.MouseUp;
  680.     Drawing := False;
  681.     Menu := GetMenu(Parent^.HWindow);
  682.     if IsRectEmpty(State^.Selection) then
  683.     begin
  684.       DisableCCD;
  685.       EnableUndo;
  686.     end
  687.     else
  688.     begin
  689.       DC := GetDC(HWindow);
  690.       PaintSelection(DC, False);
  691.       ReleaseDC(HWindow, DC);
  692.       EnableCCD;
  693.       DisableUndo;
  694.     end;
  695.   end;
  696. end;
  697.  
  698. { When the cursor is over the canvas, change the cursor to the cursor
  699.   associated with the selected tool. If the cursor is over the selection
  700.   use the standard arrow cursor.
  701. }
  702. procedure TCanvas.WMSetCursor(var Msg: TMessage);
  703. var
  704.   Pt: TPoint;            { Cursor position }
  705.   R: TRect;            { Window client area }
  706. begin
  707.   GetCursorPos(Pt);        { In global coordinates }
  708.   ScreenToClient(HWindow, Pt);  { In window client local coordinates }
  709.   GetClientRect(HWindow, R);
  710.   if not(PtInRect(R, Pt)) or PtInRect(State^.Selection, Pt) then
  711.     SetCursor(LoadCursor(0, idc_Arrow))
  712.   else
  713.     SetCursor(State^.PaintTool^.Cursor)
  714. end;
  715.  
  716. { TCanvasScroller }
  717. procedure TCanvasScroller.BeginView(PaintDC: HDC; var PaintInfo: TPaintStruct);
  718. var
  719.   R: TRect;
  720.   DX, DY: Integer;
  721. begin
  722.   TScroller.BeginView(PaintDC, PaintInfo);
  723.   with PCanvas(Window)^.State^ do
  724.   begin
  725.     DX := XPos - Offset.X;
  726.     DY := YPos - Offset.Y;
  727.     if not(IsRectEmpty(Selection)) then
  728.       with Selection do
  729.     SetRect(Selection, Left - DX, Top - DY, Right - DX, Bottom - DY);
  730.     Offset.X := XPos;
  731.     Offset.Y := YPos;
  732.   end;
  733. end;
  734.  
  735. end.
  736.